<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Vue3 进阶 | ShuangChenYue</title>
    <meta name="generator" content="VuePress 1.9.10">
    <link rel="icon" href="https://cdn.jsdelivr.net/gh/cmty256/imgs-blog@main/logo/白云.38zbldnhh180.jpg">
    <meta name="description" content="满招损，谦受益">
    <meta name="keywords" content="专注于Cpp语言的旅行者">
    
    <link rel="preload" href="/assets/css/0.styles.952d6952.css" as="style"><link rel="preload" href="/assets/js/app.67adcfd9.js" as="script"><link rel="preload" href="/assets/js/4.9aaa1650.js" as="script"><link rel="preload" href="/assets/js/1.5474518c.js" as="script"><link rel="preload" href="/assets/js/3.593d14fc.js" as="script"><link rel="preload" href="/assets/js/171.38820827.js" as="script"><link rel="prefetch" href="/assets/js/10.3242746b.js"><link rel="prefetch" href="/assets/js/100.9224de43.js"><link rel="prefetch" href="/assets/js/101.f0d1b059.js"><link rel="prefetch" href="/assets/js/102.996bfc6d.js"><link rel="prefetch" href="/assets/js/103.9bfdbd6f.js"><link rel="prefetch" href="/assets/js/104.8613f283.js"><link rel="prefetch" href="/assets/js/105.aa6e809e.js"><link rel="prefetch" href="/assets/js/106.90192392.js"><link rel="prefetch" href="/assets/js/107.e82a40b7.js"><link rel="prefetch" href="/assets/js/108.994cd438.js"><link rel="prefetch" href="/assets/js/109.ec15acc2.js"><link rel="prefetch" href="/assets/js/11.c04b41c1.js"><link rel="prefetch" href="/assets/js/110.c32d8576.js"><link rel="prefetch" href="/assets/js/111.453b5d50.js"><link rel="prefetch" href="/assets/js/112.ffbdb3a4.js"><link rel="prefetch" href="/assets/js/113.12b8ad7d.js"><link rel="prefetch" href="/assets/js/114.899d2998.js"><link rel="prefetch" href="/assets/js/115.b7ad9576.js"><link rel="prefetch" href="/assets/js/116.a8394748.js"><link rel="prefetch" href="/assets/js/117.0edfe25b.js"><link rel="prefetch" href="/assets/js/118.9161b1fe.js"><link rel="prefetch" href="/assets/js/119.be59e21b.js"><link rel="prefetch" href="/assets/js/12.41437bf6.js"><link rel="prefetch" href="/assets/js/120.bcf439fb.js"><link rel="prefetch" href="/assets/js/121.c3d251b8.js"><link rel="prefetch" href="/assets/js/122.62b1caba.js"><link rel="prefetch" href="/assets/js/123.787c2ab0.js"><link rel="prefetch" href="/assets/js/124.a880746f.js"><link rel="prefetch" href="/assets/js/125.d8edfe7b.js"><link rel="prefetch" href="/assets/js/126.4ff01546.js"><link rel="prefetch" href="/assets/js/127.9416d1ff.js"><link rel="prefetch" href="/assets/js/128.01a4a7a0.js"><link rel="prefetch" href="/assets/js/129.76876665.js"><link rel="prefetch" href="/assets/js/13.922328e9.js"><link rel="prefetch" href="/assets/js/130.7f631dd9.js"><link rel="prefetch" href="/assets/js/131.c9e0fde9.js"><link rel="prefetch" href="/assets/js/132.1c04cde5.js"><link rel="prefetch" href="/assets/js/133.e8f381cd.js"><link rel="prefetch" href="/assets/js/134.03d19f8b.js"><link rel="prefetch" href="/assets/js/135.44607494.js"><link rel="prefetch" href="/assets/js/136.6a1eb3c9.js"><link rel="prefetch" href="/assets/js/137.27898fd1.js"><link rel="prefetch" href="/assets/js/138.5bc0cf54.js"><link rel="prefetch" href="/assets/js/139.c2d1addc.js"><link rel="prefetch" href="/assets/js/14.e54d7526.js"><link rel="prefetch" href="/assets/js/140.052ec8e4.js"><link rel="prefetch" href="/assets/js/141.131abb5a.js"><link rel="prefetch" href="/assets/js/142.6ba6c07b.js"><link rel="prefetch" href="/assets/js/143.5dd51d22.js"><link rel="prefetch" href="/assets/js/144.b45afca8.js"><link rel="prefetch" href="/assets/js/145.faa9fb04.js"><link rel="prefetch" href="/assets/js/146.b54c024d.js"><link rel="prefetch" href="/assets/js/147.a1223242.js"><link rel="prefetch" href="/assets/js/148.4767bcb2.js"><link rel="prefetch" href="/assets/js/149.b65ab046.js"><link rel="prefetch" href="/assets/js/15.7082a3da.js"><link rel="prefetch" href="/assets/js/150.9bd8c175.js"><link rel="prefetch" href="/assets/js/151.9f830e96.js"><link rel="prefetch" href="/assets/js/152.41cde7f0.js"><link rel="prefetch" href="/assets/js/153.f57d65e0.js"><link rel="prefetch" href="/assets/js/154.5d7c8d51.js"><link rel="prefetch" href="/assets/js/155.0ae99532.js"><link rel="prefetch" href="/assets/js/156.5a54e043.js"><link rel="prefetch" href="/assets/js/157.c25b5d40.js"><link rel="prefetch" href="/assets/js/158.aa025b46.js"><link rel="prefetch" href="/assets/js/159.47939d88.js"><link rel="prefetch" href="/assets/js/16.fc775b7b.js"><link rel="prefetch" href="/assets/js/160.f8624459.js"><link rel="prefetch" href="/assets/js/161.7a075dc2.js"><link rel="prefetch" href="/assets/js/162.1d48f266.js"><link rel="prefetch" href="/assets/js/163.5d68a99f.js"><link rel="prefetch" href="/assets/js/164.1262d0e5.js"><link rel="prefetch" href="/assets/js/165.2ccf0bdd.js"><link rel="prefetch" href="/assets/js/166.21ece4d9.js"><link rel="prefetch" href="/assets/js/167.bf8adb95.js"><link rel="prefetch" href="/assets/js/168.1cb8440d.js"><link rel="prefetch" href="/assets/js/169.1dd1e396.js"><link rel="prefetch" href="/assets/js/17.ecc7be70.js"><link rel="prefetch" href="/assets/js/170.c29ec18f.js"><link rel="prefetch" href="/assets/js/172.bbc8ffc6.js"><link rel="prefetch" href="/assets/js/173.470e21e7.js"><link rel="prefetch" href="/assets/js/174.3c2df318.js"><link rel="prefetch" href="/assets/js/175.d2690cdb.js"><link rel="prefetch" href="/assets/js/176.9ca64696.js"><link rel="prefetch" href="/assets/js/177.76f3271d.js"><link rel="prefetch" href="/assets/js/178.d7d9def2.js"><link rel="prefetch" href="/assets/js/179.b5644743.js"><link rel="prefetch" href="/assets/js/18.31fe7ecd.js"><link rel="prefetch" href="/assets/js/180.7592d5ef.js"><link rel="prefetch" href="/assets/js/181.5cb77d35.js"><link rel="prefetch" href="/assets/js/182.6fa5633c.js"><link rel="prefetch" href="/assets/js/183.b3a53d1b.js"><link rel="prefetch" href="/assets/js/184.3815c537.js"><link rel="prefetch" href="/assets/js/185.bcf4ab71.js"><link rel="prefetch" href="/assets/js/186.1cc02f6d.js"><link rel="prefetch" href="/assets/js/187.8b425fb7.js"><link rel="prefetch" href="/assets/js/188.44ccbd02.js"><link rel="prefetch" href="/assets/js/189.353b35e3.js"><link rel="prefetch" href="/assets/js/19.520992d5.js"><link rel="prefetch" href="/assets/js/190.c284595f.js"><link rel="prefetch" href="/assets/js/191.788ecc2d.js"><link rel="prefetch" href="/assets/js/192.712a164e.js"><link rel="prefetch" href="/assets/js/193.da58aba3.js"><link rel="prefetch" href="/assets/js/194.6b1b1f4d.js"><link rel="prefetch" href="/assets/js/195.c31d5c39.js"><link rel="prefetch" href="/assets/js/196.f6670c4d.js"><link rel="prefetch" href="/assets/js/197.5a1f50ab.js"><link rel="prefetch" href="/assets/js/2.ab565158.js"><link rel="prefetch" href="/assets/js/20.69e29cdc.js"><link rel="prefetch" href="/assets/js/21.2fd424ad.js"><link rel="prefetch" href="/assets/js/22.d4c0be54.js"><link rel="prefetch" href="/assets/js/23.4bb90ecc.js"><link rel="prefetch" href="/assets/js/24.c01be6b2.js"><link rel="prefetch" href="/assets/js/25.c8833687.js"><link rel="prefetch" href="/assets/js/26.8042b555.js"><link rel="prefetch" href="/assets/js/27.0d5fa4c0.js"><link rel="prefetch" href="/assets/js/28.f9735b8b.js"><link rel="prefetch" href="/assets/js/29.3af53626.js"><link rel="prefetch" href="/assets/js/30.5f1b56d1.js"><link rel="prefetch" href="/assets/js/31.544b2649.js"><link rel="prefetch" href="/assets/js/32.aa321988.js"><link rel="prefetch" href="/assets/js/33.6aba2c86.js"><link rel="prefetch" href="/assets/js/34.e1bbff24.js"><link rel="prefetch" href="/assets/js/35.233f76e0.js"><link rel="prefetch" href="/assets/js/36.cb773972.js"><link rel="prefetch" href="/assets/js/37.393d9c59.js"><link rel="prefetch" href="/assets/js/38.e2d530c5.js"><link rel="prefetch" href="/assets/js/39.acaf1cc0.js"><link rel="prefetch" href="/assets/js/40.358f731e.js"><link rel="prefetch" href="/assets/js/41.ded24b7e.js"><link rel="prefetch" href="/assets/js/42.b9f683c3.js"><link rel="prefetch" href="/assets/js/43.c8fb3e66.js"><link rel="prefetch" href="/assets/js/44.633142da.js"><link rel="prefetch" href="/assets/js/45.6095e772.js"><link rel="prefetch" href="/assets/js/46.421d8c7a.js"><link rel="prefetch" href="/assets/js/47.da50fe47.js"><link rel="prefetch" href="/assets/js/48.15ff5726.js"><link rel="prefetch" href="/assets/js/49.b662e624.js"><link rel="prefetch" href="/assets/js/5.c1b8a209.js"><link rel="prefetch" href="/assets/js/50.a8bc75df.js"><link rel="prefetch" href="/assets/js/51.51e36ae7.js"><link rel="prefetch" href="/assets/js/52.54cc6e51.js"><link rel="prefetch" href="/assets/js/53.4173561d.js"><link rel="prefetch" href="/assets/js/54.7cab8416.js"><link rel="prefetch" href="/assets/js/55.3d7317d3.js"><link rel="prefetch" href="/assets/js/56.3c22255b.js"><link rel="prefetch" href="/assets/js/57.18e46e30.js"><link rel="prefetch" href="/assets/js/58.aad57f31.js"><link rel="prefetch" href="/assets/js/59.7897f6a7.js"><link rel="prefetch" href="/assets/js/6.3131f88a.js"><link rel="prefetch" href="/assets/js/60.5cd0051a.js"><link rel="prefetch" href="/assets/js/61.d9606403.js"><link rel="prefetch" href="/assets/js/62.aede9df0.js"><link rel="prefetch" href="/assets/js/63.2c30e554.js"><link rel="prefetch" href="/assets/js/64.18228ab7.js"><link rel="prefetch" href="/assets/js/65.27cb3fba.js"><link rel="prefetch" href="/assets/js/66.2fa6c2dc.js"><link rel="prefetch" href="/assets/js/67.d274a8df.js"><link rel="prefetch" href="/assets/js/68.3069cfcf.js"><link rel="prefetch" href="/assets/js/69.4c28600f.js"><link rel="prefetch" href="/assets/js/7.89e6165d.js"><link rel="prefetch" href="/assets/js/70.4175440c.js"><link rel="prefetch" href="/assets/js/71.2ee6b435.js"><link rel="prefetch" href="/assets/js/72.c75e3bb8.js"><link rel="prefetch" href="/assets/js/73.6f8b8211.js"><link rel="prefetch" href="/assets/js/74.6c7720cf.js"><link rel="prefetch" href="/assets/js/75.cccfb229.js"><link rel="prefetch" href="/assets/js/76.f022e5da.js"><link rel="prefetch" href="/assets/js/77.dab46206.js"><link rel="prefetch" href="/assets/js/78.ca574b2a.js"><link rel="prefetch" href="/assets/js/79.3d75e618.js"><link rel="prefetch" href="/assets/js/80.091749b1.js"><link rel="prefetch" href="/assets/js/81.14db0e21.js"><link rel="prefetch" href="/assets/js/82.8a2b1809.js"><link rel="prefetch" href="/assets/js/83.84a4b599.js"><link rel="prefetch" href="/assets/js/84.11d7c222.js"><link rel="prefetch" href="/assets/js/85.273d4388.js"><link rel="prefetch" href="/assets/js/86.fb40e20c.js"><link rel="prefetch" href="/assets/js/87.3316639e.js"><link rel="prefetch" href="/assets/js/88.dfc52200.js"><link rel="prefetch" href="/assets/js/89.8d615f6e.js"><link rel="prefetch" href="/assets/js/90.1d9f08bb.js"><link rel="prefetch" href="/assets/js/91.566813e7.js"><link rel="prefetch" href="/assets/js/92.d13c6f41.js"><link rel="prefetch" href="/assets/js/93.845c42a0.js"><link rel="prefetch" href="/assets/js/94.20a37b77.js"><link rel="prefetch" href="/assets/js/95.1a498005.js"><link rel="prefetch" href="/assets/js/96.39fa7f4b.js"><link rel="prefetch" href="/assets/js/97.50f7170e.js"><link rel="prefetch" href="/assets/js/98.dd2e15d6.js"><link rel="prefetch" href="/assets/js/99.ef7ea06a.js"><link rel="prefetch" href="/assets/js/vendors~docsearch.ae6b1de9.js">
    <link rel="stylesheet" href="/assets/css/0.styles.952d6952.css">
  </head>
  <body class="theme-mode-light">
    <div id="app" data-server-rendered="true"><div class="theme-container sidebar-open have-rightmenu"><header class="navbar blur"><div title="目录" class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="https://cdn.jsdelivr.net/gh/cmty256/imgs-blog@main/logo/白云.38zbldnhh180.jpg" alt="ShuangChenYue" class="logo"> <span class="site-name can-hide">ShuangChenYue</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="CPP语言" class="dropdown-title"><!----> <span class="title" style="display:;">CPP语言</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/c5bdd8/" class="nav-link">Cpp之旅</a></li><li class="dropdown-item"><!----> <a href="/pages/279e62/" class="nav-link">Cpp专栏</a></li><li class="dropdown-item"><!----> <a href="/pages/801755/" class="nav-link">Effective_CPP</a></li><li class="dropdown-item"><!----> <a href="/pages/6b2468/" class="nav-link">muduo网络库</a></li><li class="dropdown-item"><!----> <a href="/pages/5f8c9f/" class="nav-link">Unix环境高级编程</a></li><li class="dropdown-item"><!----> <a href="/pages/3f1d21/" class="nav-link">Cpp提高编程</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="计算机基础" class="dropdown-title"><!----> <span class="title" style="display:;">计算机基础</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/7b1cb2/" class="nav-link">计算机网络</a></li><li class="dropdown-item"><!----> <a href="/pages/6048a8/" class="nav-link">操作系统</a></li><li class="dropdown-item"><!----> <a href="/pages/3b34ba/" class="nav-link">数据结构</a></li><li class="dropdown-item"><!----> <a href="/pages/412fe7/" class="nav-link">Linux</a></li><li class="dropdown-item"><!----> <a href="/pages/2dcfa1/" class="nav-link">算法</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="数据库" class="dropdown-title"><!----> <span class="title" style="display:;">数据库</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/efa3f2/" class="nav-link">基础篇</a></li><li class="dropdown-item"><!----> <a href="/pages/ccc445/" class="nav-link">MySql</a></li><li class="dropdown-item"><!----> <a href="/pages/54616e/" class="nav-link">Redis</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="嵌入式软件开发" class="dropdown-title"><!----> <span class="title" style="display:;">嵌入式软件开发</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/d142c2/" class="nav-link">电子嵌入式通信协议</a></li><li class="dropdown-item"><!----> <a href="/pages/4c6bf3/" class="nav-link">深入浅出SSD</a></li><li class="dropdown-item"><!----> <a href="/pages/d3f36a/" class="nav-link">文件系统</a></li><li class="dropdown-item"><!----> <a href="/pages/e0cca7/" class="nav-link">汇编语言</a></li><li class="dropdown-item"><!----> <a href="/pages/fab2d7/" class="nav-link">STM32</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="开发日常" class="dropdown-title"><!----> <span class="title" style="display:;">开发日常</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/e472d1/" class="nav-link">随笔（持续更新）</a></li><li class="dropdown-item"><!----> <a href="/pages/71f6ae/" class="nav-link">Git知识总结</a></li><li class="dropdown-item"><!----> <a href="/pages/db6fb8/" class="nav-link">Git备忘清单</a></li><li class="dropdown-item"><!----> <a href="/pages/e1081f/" class="nav-link">Git 创建删除远程分支</a></li><li class="dropdown-item"><!----> <a href="/pages/777b8a/" class="nav-link">nvm使用小结</a></li><li class="dropdown-item"><!----> <a href="/pages/ee770e/" class="nav-link">虚拟机固定 IP 地址</a></li><li class="dropdown-item"><!----> <a href="/pages/1ab9a6/" class="nav-link">Shell 脚本学习笔记</a></li><li class="dropdown-item"><!----> <a href="/pages/411aa4/" class="nav-link">VScode 插件 CodeGeeX 使用教程</a></li><li class="dropdown-item"><!----> <a href="/pages/0d525d/" class="nav-link">KylinV10 将项目上传至 Github教程</a></li><li class="dropdown-item"><!----> <a href="/pages/907786/" class="nav-link">KylinV10 安装 MySQL 教程（可防踩雷）</a></li><li class="dropdown-item"><!----> <a href="/pages/a2d21e/" class="nav-link">kylinV10-SP1 安装 QT</a></li><li class="dropdown-item"><!----> <a href="/pages/b561cf/" class="nav-link">高并发内存池</a></li><li class="dropdown-item"><!----> <a href="/pages/6ab6d1/" class="nav-link">USBGUARD 项目编译环境配置</a></li><li class="dropdown-item"><!----> <a href="/pages/883f02/" class="nav-link">Power_Destory 项目</a></li><li class="dropdown-item"><!----> <a href="/pages/479472/" class="nav-link">U 盘清除工具编译教程</a></li><li class="dropdown-item"><!----> <a href="/pages/9c4241/" class="nav-link">个人博客代码推送教程</a></li><li class="dropdown-item"><!----> <a href="/pages/3ad765/" class="nav-link">SVN Trunk Branches的Merge操作</a></li><li class="dropdown-item"><!----> <a href="/pages/0c0ca8/" class="nav-link">如何高效阅读嵌入式项目代码</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端学习" class="dropdown-title"><!----> <span class="title" style="display:;">前端学习</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/99897f/" class="nav-link">HTML与CSS</a></li><li class="dropdown-item"><!----> <a href="/pages/51542d/" class="nav-link">JS学习</a></li><li class="dropdown-item"><!----> <a href="/pages/803f9d/" class="nav-link">Vue3入门</a></li><li class="dropdown-item"><!----> <a href="/pages/ca4cfb/" aria-current="page" class="nav-link router-link-exact-active router-link-active">Vue3进阶</a></li><li class="dropdown-item"><!----> <a href="/pages/50e8d3/" class="nav-link">黑马Vue3</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="MFC" class="dropdown-title"><!----> <span class="title" style="display:;">MFC</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/a4b108/" class="nav-link">MFC编程随记</a></li><li class="dropdown-item"><!----> <a href="/pages/41acbd/" class="nav-link">MFC实现ini配置文件的读取</a></li><li class="dropdown-item"><!----> <a href="/pages/951a7a/" class="nav-link">MFC实现点击列表头排序</a></li><li class="dropdown-item"><!----> <a href="/pages/a8598f/" class="nav-link">贴图法美化Button按钮</a></li><li class="dropdown-item"><!----> <a href="/pages/054516/" class="nav-link">MFC使用细节</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="闪存" class="dropdown-title"><!----> <span class="title" style="display:;">闪存</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/b925b8/" class="nav-link">如何高效阅读嵌入式项目代码</a></li><li class="dropdown-item"><!----> <a href="/pages/28ec23/" class="nav-link">NAND Flash</a></li><li class="dropdown-item"><!----> <a href="/pages/62bf40/" class="nav-link">ARM 处理器</a></li><li class="dropdown-item"><!----> <a href="/pages/1a9374/" class="nav-link">嵌入式基础知识-存储器</a></li><li class="dropdown-item"><!----> <a href="/pages/aac5e3/" class="nav-link">闪存存储和制造技术概述</a></li><li class="dropdown-item"><!----> <a href="/pages/8f6056/" class="nav-link">芯片IO驱动力</a></li><li class="dropdown-item"><!----> <a href="/pages/d146b8/" class="nav-link">主流先进封装技术介绍</a></li><li class="dropdown-item"><!----> <a href="/pages/16f0ba/" class="nav-link">NAND Flash基础</a></li><li class="dropdown-item"><!----> <a href="/pages/90d8d0/" class="nav-link">基于PA算法的FTL引导</a></li><li class="dropdown-item"><!----> <a href="/pages/eb672b/" class="nav-link">SD逻辑擦除和物理擦除</a></li><li class="dropdown-item"><!----> <a href="/pages/747121/" class="nav-link">NAND Flash的SDR、ONFI、DDR接口</a></li><li class="dropdown-item"><!----> <a href="/pages/1eb351/" class="nav-link">【详解】Nand Flash必看知识</a></li><li class="dropdown-item"><!----> <a href="/pages/d2512a/" class="nav-link">【两万字详解】Nand Flash必看知识</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="面经" class="dropdown-title"><!----> <span class="title" style="display:;">面经</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/d69946/" class="nav-link">虎牙C++技术面经</a></li><li class="dropdown-item"><!----> <a href="/pages/29251d/" class="nav-link">金山一面复习</a></li><li class="dropdown-item"><!----> <a href="/pages/c7c01f/" class="nav-link">完美世界秋招 C++ 游戏开发面经(Cpp部分)</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="其它" class="dropdown-title"><!----> <span class="title" style="display:;">其它</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/fa256e/" class="nav-link">博客搭建</a></li><li class="dropdown-item"><!----> <a href="/pages/335531/" class="nav-link">网站收藏箱</a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <div class="sidebar-hover-trigger"></div> <aside class="sidebar" style="display:none;"><!----> <nav class="nav-links"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="CPP语言" class="dropdown-title"><!----> <span class="title" style="display:;">CPP语言</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/c5bdd8/" class="nav-link">Cpp之旅</a></li><li class="dropdown-item"><!----> <a href="/pages/279e62/" class="nav-link">Cpp专栏</a></li><li class="dropdown-item"><!----> <a href="/pages/801755/" class="nav-link">Effective_CPP</a></li><li class="dropdown-item"><!----> <a href="/pages/6b2468/" class="nav-link">muduo网络库</a></li><li class="dropdown-item"><!----> <a href="/pages/5f8c9f/" class="nav-link">Unix环境高级编程</a></li><li class="dropdown-item"><!----> <a href="/pages/3f1d21/" class="nav-link">Cpp提高编程</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="计算机基础" class="dropdown-title"><!----> <span class="title" style="display:;">计算机基础</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/7b1cb2/" class="nav-link">计算机网络</a></li><li class="dropdown-item"><!----> <a href="/pages/6048a8/" class="nav-link">操作系统</a></li><li class="dropdown-item"><!----> <a href="/pages/3b34ba/" class="nav-link">数据结构</a></li><li class="dropdown-item"><!----> <a href="/pages/412fe7/" class="nav-link">Linux</a></li><li class="dropdown-item"><!----> <a href="/pages/2dcfa1/" class="nav-link">算法</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="数据库" class="dropdown-title"><!----> <span class="title" style="display:;">数据库</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/efa3f2/" class="nav-link">基础篇</a></li><li class="dropdown-item"><!----> <a href="/pages/ccc445/" class="nav-link">MySql</a></li><li class="dropdown-item"><!----> <a href="/pages/54616e/" class="nav-link">Redis</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="嵌入式软件开发" class="dropdown-title"><!----> <span class="title" style="display:;">嵌入式软件开发</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/d142c2/" class="nav-link">电子嵌入式通信协议</a></li><li class="dropdown-item"><!----> <a href="/pages/4c6bf3/" class="nav-link">深入浅出SSD</a></li><li class="dropdown-item"><!----> <a href="/pages/d3f36a/" class="nav-link">文件系统</a></li><li class="dropdown-item"><!----> <a href="/pages/e0cca7/" class="nav-link">汇编语言</a></li><li class="dropdown-item"><!----> <a href="/pages/fab2d7/" class="nav-link">STM32</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="开发日常" class="dropdown-title"><!----> <span class="title" style="display:;">开发日常</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/e472d1/" class="nav-link">随笔（持续更新）</a></li><li class="dropdown-item"><!----> <a href="/pages/71f6ae/" class="nav-link">Git知识总结</a></li><li class="dropdown-item"><!----> <a href="/pages/db6fb8/" class="nav-link">Git备忘清单</a></li><li class="dropdown-item"><!----> <a href="/pages/e1081f/" class="nav-link">Git 创建删除远程分支</a></li><li class="dropdown-item"><!----> <a href="/pages/777b8a/" class="nav-link">nvm使用小结</a></li><li class="dropdown-item"><!----> <a href="/pages/ee770e/" class="nav-link">虚拟机固定 IP 地址</a></li><li class="dropdown-item"><!----> <a href="/pages/1ab9a6/" class="nav-link">Shell 脚本学习笔记</a></li><li class="dropdown-item"><!----> <a href="/pages/411aa4/" class="nav-link">VScode 插件 CodeGeeX 使用教程</a></li><li class="dropdown-item"><!----> <a href="/pages/0d525d/" class="nav-link">KylinV10 将项目上传至 Github教程</a></li><li class="dropdown-item"><!----> <a href="/pages/907786/" class="nav-link">KylinV10 安装 MySQL 教程（可防踩雷）</a></li><li class="dropdown-item"><!----> <a href="/pages/a2d21e/" class="nav-link">kylinV10-SP1 安装 QT</a></li><li class="dropdown-item"><!----> <a href="/pages/b561cf/" class="nav-link">高并发内存池</a></li><li class="dropdown-item"><!----> <a href="/pages/6ab6d1/" class="nav-link">USBGUARD 项目编译环境配置</a></li><li class="dropdown-item"><!----> <a href="/pages/883f02/" class="nav-link">Power_Destory 项目</a></li><li class="dropdown-item"><!----> <a href="/pages/479472/" class="nav-link">U 盘清除工具编译教程</a></li><li class="dropdown-item"><!----> <a href="/pages/9c4241/" class="nav-link">个人博客代码推送教程</a></li><li class="dropdown-item"><!----> <a href="/pages/3ad765/" class="nav-link">SVN Trunk Branches的Merge操作</a></li><li class="dropdown-item"><!----> <a href="/pages/0c0ca8/" class="nav-link">如何高效阅读嵌入式项目代码</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端学习" class="dropdown-title"><!----> <span class="title" style="display:;">前端学习</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/99897f/" class="nav-link">HTML与CSS</a></li><li class="dropdown-item"><!----> <a href="/pages/51542d/" class="nav-link">JS学习</a></li><li class="dropdown-item"><!----> <a href="/pages/803f9d/" class="nav-link">Vue3入门</a></li><li class="dropdown-item"><!----> <a href="/pages/ca4cfb/" aria-current="page" class="nav-link router-link-exact-active router-link-active">Vue3进阶</a></li><li class="dropdown-item"><!----> <a href="/pages/50e8d3/" class="nav-link">黑马Vue3</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="MFC" class="dropdown-title"><!----> <span class="title" style="display:;">MFC</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/a4b108/" class="nav-link">MFC编程随记</a></li><li class="dropdown-item"><!----> <a href="/pages/41acbd/" class="nav-link">MFC实现ini配置文件的读取</a></li><li class="dropdown-item"><!----> <a href="/pages/951a7a/" class="nav-link">MFC实现点击列表头排序</a></li><li class="dropdown-item"><!----> <a href="/pages/a8598f/" class="nav-link">贴图法美化Button按钮</a></li><li class="dropdown-item"><!----> <a href="/pages/054516/" class="nav-link">MFC使用细节</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="闪存" class="dropdown-title"><!----> <span class="title" style="display:;">闪存</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/b925b8/" class="nav-link">如何高效阅读嵌入式项目代码</a></li><li class="dropdown-item"><!----> <a href="/pages/28ec23/" class="nav-link">NAND Flash</a></li><li class="dropdown-item"><!----> <a href="/pages/62bf40/" class="nav-link">ARM 处理器</a></li><li class="dropdown-item"><!----> <a href="/pages/1a9374/" class="nav-link">嵌入式基础知识-存储器</a></li><li class="dropdown-item"><!----> <a href="/pages/aac5e3/" class="nav-link">闪存存储和制造技术概述</a></li><li class="dropdown-item"><!----> <a href="/pages/8f6056/" class="nav-link">芯片IO驱动力</a></li><li class="dropdown-item"><!----> <a href="/pages/d146b8/" class="nav-link">主流先进封装技术介绍</a></li><li class="dropdown-item"><!----> <a href="/pages/16f0ba/" class="nav-link">NAND Flash基础</a></li><li class="dropdown-item"><!----> <a href="/pages/90d8d0/" class="nav-link">基于PA算法的FTL引导</a></li><li class="dropdown-item"><!----> <a href="/pages/eb672b/" class="nav-link">SD逻辑擦除和物理擦除</a></li><li class="dropdown-item"><!----> <a href="/pages/747121/" class="nav-link">NAND Flash的SDR、ONFI、DDR接口</a></li><li class="dropdown-item"><!----> <a href="/pages/1eb351/" class="nav-link">【详解】Nand Flash必看知识</a></li><li class="dropdown-item"><!----> <a href="/pages/d2512a/" class="nav-link">【两万字详解】Nand Flash必看知识</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="面经" class="dropdown-title"><!----> <span class="title" style="display:;">面经</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/d69946/" class="nav-link">虎牙C++技术面经</a></li><li class="dropdown-item"><!----> <a href="/pages/29251d/" class="nav-link">金山一面复习</a></li><li class="dropdown-item"><!----> <a href="/pages/c7c01f/" class="nav-link">完美世界秋招 C++ 游戏开发面经(Cpp部分)</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="其它" class="dropdown-title"><!----> <span class="title" style="display:;">其它</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/fa256e/" class="nav-link">博客搭建</a></li><li class="dropdown-item"><!----> <a href="/pages/335531/" class="nav-link">网站收藏箱</a></li></ul></div></div> <!----></nav>  <ul class="sidebar-links"><li><a href="/pages/99897f/" class="sidebar-link">HTML与CSS</a></li><li><a href="/pages/51542d/" class="sidebar-link">js学习</a></li><li><a href="/pages/803f9d/" class="sidebar-link">Vue3入门</a></li><li><a href="/pages/ca4cfb/" aria-current="page" class="active sidebar-link">Vue3 进阶</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level2"><a href="/pages/ca4cfb/#任务一-创建-vite-vue3-单页应用" class="sidebar-link">任务一 创建 Vite + Vue3 单页应用</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#单页应用" class="sidebar-link">单页应用</a></li><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#vue-3-对单页应用开发的支持" class="sidebar-link">Vue 3 对单页应用开发的支持</a></li><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#安装-node-js" class="sidebar-link">安装 Node.js</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#一、下载-node-js" class="sidebar-link">一、下载 Node.js</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#二、安装-node-js" class="sidebar-link">二、安装 Node.js</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#三、测试安装是否成功" class="sidebar-link">三、测试安装是否成功</a></li><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#创建-vite-vue3-单页应用" class="sidebar-link">创建 Vite+Vue3 单页应用</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#一、创建项目" class="sidebar-link">一、创建项目</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#二、安装依赖" class="sidebar-link">二、安装依赖</a></li><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#运行单页应用" class="sidebar-link">运行单页应用</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#一、启动项目服务端" class="sidebar-link">一、启动项目服务端</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#二、从浏览器访问应用" class="sidebar-link">二、从浏览器访问应用</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/ca4cfb/#任务二-了解组合式-api" class="sidebar-link">任务二 了解组合式 API</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#使用-setup-函数" class="sidebar-link">使用 setup 函数</a></li><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#使用-script-setup" class="sidebar-link">使用 script setup</a></li><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#引入-typescript" class="sidebar-link">引入 TypeScript</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/ca4cfb/#响应式" class="sidebar-link">响应式</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#vue-3-的响应式原理" class="sidebar-link">Vue 3 的响应式原理</a></li><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#vue-3-的响应式-api" class="sidebar-link">Vue 3 的响应式 API</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/ca4cfb/#任务三-用-reactive-设置响应式数据" class="sidebar-link">任务三 用 reactive 设置响应式数据</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#reactive-函数的原理及注意事项" class="sidebar-link">reactive 函数的原理及注意事项</a></li><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#reactive-的使用举例" class="sidebar-link">reactive 的使用举例</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#一、reactive-作用于普通的-javascript-对象" class="sidebar-link">一、reactive 作用于普通的 JavaScript 对象</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#二、reactive-作用于数组" class="sidebar-link">二、reactive 作用于数组</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/ca4cfb/#任务四-用-ref-设置响应式数据" class="sidebar-link">任务四 用 ref 设置响应式数据</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#ref-的原理及注意事项" class="sidebar-link">ref 的原理及注意事项</a></li><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#ref-的使用举例" class="sidebar-link">ref 的使用举例</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/ca4cfb/#任务五-toref-与-torefs" class="sidebar-link">任务五 toRef() 与 toRefs()</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#toref-的使用场景" class="sidebar-link">toRef() 的使用场景</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#_1-问题引入" class="sidebar-link">1 问题引入</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#_2-解决办法" class="sidebar-link">2 解决办法</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#_3-继续改进" class="sidebar-link">3 继续改进</a></li><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#torefs-的使用场景" class="sidebar-link">toRefs() 的使用场景</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#一、问题引入" class="sidebar-link">一、问题引入</a></li><li class="sidebar-sub-header level4"><a href="/pages/ca4cfb/#二、解决办法" class="sidebar-link">二、解决办法</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/ca4cfb/#任务六-computed-与计算属性" class="sidebar-link">任务六 computed 与计算属性</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#基本概念" class="sidebar-link">基本概念</a></li><li class="sidebar-sub-header level3"><a href="/pages/ca4cfb/#使用计算属性" class="sidebar-link">使用计算属性</a></li></ul></li></ul></li><li><a href="/pages/50e8d3/" class="sidebar-link">黑马Vue3</a></li></ul> </aside> <div><main class="page"><div class="theme-vdoing-wrapper "><div class="articleInfo-wrap" data-v-06225672><div class="articleInfo" data-v-06225672><ul class="breadcrumbs" data-v-06225672><li data-v-06225672><a href="/" title="首页" class="iconfont icon-home router-link-active" data-v-06225672></a></li> <li data-v-06225672><span data-v-06225672>前端学习</span></li></ul> <div class="info" data-v-06225672><div title="作者" class="author iconfont icon-touxiang" data-v-06225672><a href="javascript:;" data-v-06225672>霜晨月</a></div> <div title="创建时间" class="date iconfont icon-riqi" data-v-06225672><a href="javascript:;" data-v-06225672>2023-07-08</a></div> <!----></div></div></div> <!----> <div class="content-wrapper"><div class="right-menu-wrapper"><div class="right-menu-margin"><div class="right-menu-title">目录</div> <div class="right-menu-content"></div></div></div> <h1><img src="">Vue3 进阶<!----></h1> <!----> <div class="theme-vdoing-content content__default"><h2 id="任务一-创建-vite-vue3-单页应用"><a href="#任务一-创建-vite-vue3-单页应用" class="header-anchor">#</a> 任务一 创建 Vite + Vue3 单页应用</h2> <p>Vue 3 是一个流行的 JavaScript 前端框架，用于构建<strong>单页应用程序（SPA）</strong>。</p> <p>下面是一些创建 Vue 3 单页应用程序的方式：</p> <ul><li>Vue CLI：<strong>Vue CLI 是一个命令行界面工具</strong>，用于创建和管理 Vue 应用程序。它可以自动生成一个基于 webpack 的项目模板，提供了一些内置的插件和特性，例如 Babel、ESLint、TypeScript 等。使用 Vue CLI 可以方便地创建 Vue 单页应用程序。</li> <li>手动设置：你可以手动设置一个 Vue 3 单页应用程序。这需要你手动创建 webpack 配置文件，并安装和配置必要的插件和库，如 vue-loader、babel-loader 等。这种方式更加灵活，但需要更多的配置和知识。</li> <li>使用 Vite：<strong>Vite 是一个现代化的构建工具</strong>，用于构建 Vue 应用程序。它使用现代化的技术和原生 ES 模块作为基础，提供了一种快速、轻量级的开发体验。你可以使用 Vite 创建一个 Vue 3 单页应用程序，只需运行几个命令即可。</li></ul> <p>在本任务中，我们将使用 Vite 来创建 Vue 3 单页应用程序，因为它能够大幅简化开发流程。不过，如果您需要更加灵活的控制和定制，手动设置也是一个不错的选择。</p> <h3 id="单页应用"><a href="#单页应用" class="header-anchor">#</a> 单页应用</h3> <p>单页应用（Single Page Application，SPA）是一种 Web 应用程序的架构模式，它使用动态加载的 HTML、CSS 和 JavaScript，以及 AJAX 和 WebSockets 等技术实现<strong>无刷新</strong>页面的单页应用。</p> <blockquote><p>核心思想</p></blockquote> <p>单页应用的核心思想是：将<strong>所有的页面都加载到一个单一的 HTML 页面中</strong>，通过 JavaScript 操作 DOM 实现页面的动态变化。</p> <blockquote><p>数据交互过程</p></blockquote> <p>当用户与应用程序交互时，JavaScript 会通过 AJAX 或 WebSockets 等技术请求后端 API 获取数据，然后在前端通过 Vue、React 等前端框架对数据进行处理，最终更新视图，从而实现页面的刷新和动态变化。</p> <blockquote><p>优点</p></blockquote> <p>单页应用的优点是：</p> <ul><li>可以<strong>提高页面的加载速度和用户体验</strong>，因为只需要加载一次 HTML、CSS 和 JavaScript 等资源，之后就可以在前端通过 JavaScript 动态更新页面内容，而不需要重新加载整个页面。</li> <li>此外，单页应用还可以<strong>提高开发效率</strong>，因为前端可以采用组件化开发方式，将页面拆分为多个组件，每个组件可以独立开发和测试，最终再将这些组件拼接成完整的页面。</li></ul> <blockquote><p>缺点</p></blockquote> <p>但是，单页应用也有一些<strong>缺点</strong>。</p> <ul><li>首先，由于 SPA 的内容是通过 JavaScript 动态加载的，对于 SEO 来说并不友好。</li> <li>其次，SPA 需要处理前后端分离的问题，需要前端开发人员和后端开发人员共同协作完成。此外，单页应用需要处理浏览器历史记录和 URL 路由等问题，需要使用一些第三方库或框架来处理这些问题。</li></ul> <blockquote><p>多页应用</p></blockquote> <p>相比之下，多页应用（MPA）的<strong>优点</strong>是：对 SEO 友好，因为每个页面都有自己的 URL 地址和内容，便于搜索引擎进行抓取和索引。此外，多页应用还可以采用传统的服务器渲染方式，在后端渲染页面，以提高页面的加载速度和 SEO 效果。</p> <p>但是，多页应用的<strong>缺点</strong>是：页面切换需要重新加载整个页面，页面刷新和交互体验相对较差。此外，多页应用需要在前端和后端进行模板渲染，代码复杂度相对较高，开发效率相对较低。</p> <p>因此，选择单页应用（SPA）还是多页应用（MPA）取决于项目的具体需求和情况。如果项目注重用户体验和开发效率，且对 SEO 不是特别敏感，可以选择 SPA。</p> <blockquote><p>为什么 SPA 对 SEO 不友好？</p></blockquote> <p>在这句话中，SEO 指的是<strong>搜索引擎优化</strong>（Search Engine Optimization），即通过优化网站以提高其在搜索引擎中的排名和可见性。</p> <p>&quot;对于 SEO 来说并不友好&quot;指的是：单页面应用（SPA）对于传统的搜索引擎优化方法不太友好。</p> <p><strong>原因：</strong></p> <p>SPA 是一种通过 JavaScript 动态加载内容的网页应用，它使用 AJAX 和前端路由等技术实现页面的无刷新加载和内容的动态更新。</p> <p>由于 SPA 的内容大部分是在客户端通过 JavaScript 生成和加载的，而传统的搜索引擎爬虫通常只会抓取和索引【静态 HTML 页面】，因此无法直接获取和理解 SPA 中的内容。</p> <p>这导致了 SPA 在搜索引擎中的可见性和排名受到一定影响。因为搜索引擎无法像普通的 HTML 页面那样直接抓取和索引【SPA 的内容】，所以对于那些依赖搜索引擎流量的网站来说，SPA 可能无法获得足够的有机流量。</p> <p><strong>解决方法:</strong></p> <p>然而，随着搜索引擎的发展，一些搜索引擎（如Google）已经可以执行 JavaScript 并抓取 SPA 的内容。同时，也出现了一些技术和方法来解决 SPA 的 SEO 问题，例如使用预渲染技术、动态生成静态页面、使用服务器端渲染（SSR）等。这些方法可以帮助 SPA 在搜索引擎中获得更好的可见性和排名，提高其对 SEO 的友好程度。</p> <h3 id="vue-3-对单页应用开发的支持"><a href="#vue-3-对单页应用开发的支持" class="header-anchor">#</a> Vue 3 对单页应用开发的支持</h3> <p>Vue.js 是一个用于构建现代 web 应用的渐进式框架，它对开发单页应用提供了很多支持。我们习惯把 Vue.js 2.x 和 Vue.js 3.x 版本分别简称为 Vue2 和 Vue 3。</p> <p>以下是一些 Vue 3 的特性，它们可以帮助开发者<strong>更容易地创建和维护单页应用</strong>：</p> <ul><li>使用了<strong>响应式数据绑定和组件化的思想</strong>，让开发者可以快速构建高效的用户界面。</li> <li>组合式 API：这是 Vue 3 的一个新特性，它允许开发者<strong>使用函数式的方式来组织和复用组件的逻辑</strong>，而不是依赖于选项式 API 的 data、methods、computed 等属性。这样可以让组件的代码更加清晰和模块化，也可以避免命名冲突和数据依赖的问题。</li> <li>优化的虚拟 DOM：虚拟 DOM 是 Vue 的核心特性之一，它可以让开发者<strong>使用声明式的语法来渲染界面</strong>，而不需要直接操作 DOM。Vue 3 对虚拟 DOM 进行了优化，使其更加高效和灵活。例如，Vue 3 引入了静态标记（hoisting）、片段（fragments）、模块化运行时（tree-shaking）等技术，来减少不必要的渲染和内存占用。</li> <li>支持 TypeScript：TypeScript 是一种在 JavaScript 基础上<strong>增加了类型检查和其他特性的编程语言</strong>，它可以提高代码的可读性和可维护性，也可以避免一些常见的错误。Vue 3 完全支持 TypeScript，不仅在源码层面使用了 TypeScript，还提供了完善的类型声明文件，让开发者可以在编辑器中享受到智能提示和错误检测的功能。</li> <li>更多的内置组件和指令：Vue 3 提供了一些<strong>新的内置组件和指令，来增强 SPA 的交互和功能</strong>。例如，<code>&lt;teleport&gt;</code> 组件可以让开发者将子组件渲染到任意位置，<code>&lt;suspense&gt;</code> 组件可以让开发者处理异步组件的加载状态。</li></ul> <p>总之，Vue3+vite 是一种非常适合开发单页应用的技术栈，它可以让开发者享受到最新的前端技术和最佳的开发体验。</p> <h3 id="安装-node-js"><a href="#安装-node-js" class="header-anchor">#</a> 安装 Node.js</h3> <p>创建 vite+Vue3 项目需要安装 16.0 或更高版本的 Node.js。您可以在命令行中运行 <code>node -v</code> 命令来检查您是否已安装了 node 环境。如果没有安装或版本不对的话，可以按照下面的步骤进行安装。</p> <h4 id="一、下载-node-js"><a href="#一、下载-node-js" class="header-anchor">#</a> 一、下载 Node.js</h4> <p>下载地址：https://nodejs.org/zh-cn/download/</p> <p>下载长期维护版：</p> <p><img alt="image" data-src="https://cdn.jsdelivr.net/gh/cmty256/imgs-blog@main/microservice/image.xknubdfb4y8.webp" loading="lazy" class="lazy"></p> <h4 id="二、安装-node-js"><a href="#二、安装-node-js" class="header-anchor">#</a> 二、安装 Node.js</h4> <p>以 Windows 系统为例，下载 Node.js 安装包后，双击一路安装即可。安装过程，除了 Node.js 外，还会一并安装 npm 包管理器。启动 Node.js 和 npm 的命令分别是：</p> <div class="language-bash line-numbers-mode"><pre class="language-bash"><code><span class="token function">node</span>   
<span class="token function">npm</span> 
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h4 id="三、测试安装是否成功"><a href="#三、测试安装是否成功" class="header-anchor">#</a> 三、测试安装是否成功</h4> <p>安装完成后，注意测试安装是否成功，测试命令：</p> <div class="language-bash line-numbers-mode"><pre class="language-bash"><code><span class="token function">node</span> <span class="token parameter variable">-v</span>
<span class="token function">npm</span> <span class="token parameter variable">-v</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>如果显示出 Node.js 和 npm 的版本号，表明安装成功。否则，需要检查环境变量的配置。</p> <h3 id="创建-vite-vue3-单页应用"><a href="#创建-vite-vue3-单页应用" class="header-anchor">#</a> 创建 Vite+Vue3 单页应用</h3> <p>Vue CLI 和 Vite 都是用于创建 Vue 项目的构建工具。</p> <p>Vue CLI 是一个基于 Webpack 的构建工具，它提供了一个完整的项目脚手架，包括开发服务器、热重载、代码分割、ESLint 等等。</p> <p>Vite 是一个基于 ES 模块的构建工具，它使用浏览器原生的 ES 模块加载器来提供快速的开发体验。Vite 提供了零配置的开发环境，无需安装和配置 webpack 等复杂的工具，只需一个 <code>vite.config.js</code> 文件即可启动一个本地服务器，因此它可以更快地启动和重载。Vite 支持 typescript、css 预处理器、jsx 等常用的功能，并且在生产环境中也可以更快地构建。</p> <h4 id="一、创建项目"><a href="#一、创建项目" class="header-anchor">#</a> 一、创建项目</h4> <p>使用 <code>npm</code> 或 <code>pnpm</code> 命令均可创建 Vite+Vue3 单页应用：</p> <div class="language-bash line-numbers-mode"><pre class="language-bash"><code><span class="token function">npm</span> init vue@latest
或
<span class="token function">pnpm</span> create vue@latest
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>这一命令将会安装并执行 create-vue，它是 Vue 官方的项目脚手架工具。</p> <p>建议采用 <code>pnpm create vue@latest</code> 进行创建。如果没有安装 <code>pnpm</code> 的话，可以先安装 <code>pnpm</code>，安装命令为：</p> <div class="language-bash line-numbers-mode"><pre class="language-bash"><code><span class="token function">npm</span> <span class="token function">install</span> <span class="token function">pnpm</span> <span class="token parameter variable">-g</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>这里使用 <code>pnpm create vue@latest</code> 命令创建 Vue3 项目的过程中，您将会看到一些如 TypeScript 和测试支持之类的可选功能提示：</p> <p>可按需要进行选择安装，这里我们选择 <code>TypeScript</code>、<code>Vue Router</code>、<code>Pinia</code>，其余的功能可以留待以后需要时再进行安装。</p> <div class="language-plain line-numbers-mode"><pre class="language-plain"><code>✔ Project name: … &lt;your-project-name&gt;
✔ Add TypeScript? … No / Yes -- y
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes -- y
✔ Add Pinia for state management? … No / Yes -- y
✔ Add Vitest for Unit Testing? … No / Yes
✔ Add an End-to-End Testing Solution? › No
✔ Add ESLint for code quality? … No / Yes

Scaffolding project in ./&lt;your-project-name&gt;...
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>如果我们在上面第一步 Project name 处输入项目名称 RealWorld-frontend 的话，项目创建成功后，会显示如下命令序列，提示您如何进行后续操作。</p> <div class="language-bash line-numbers-mode"><pre class="language-bash"><code><span class="token builtin class-name">cd</span> realworld-frontend
<span class="token function">pnpm</span> <span class="token function">install</span>
<span class="token function">pnpm</span> dev
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>项目结构如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>├── public/                  // 公共资源目录
│   └── favicon.ico          // 网站图标
├── src/                     // 项目源码目录
│   ├── assets/              // 静态资源目录（如图片、字体等）
│   ├── components/          // 组件目录
│   ├── router/              // 路由目录
│   ├── stores/              // 状态管理目录
│   ├── views/               // 视图目录
│   ├── App.vue              // 根组件
│   └── main.ts              // 项目入口文件
├── .gitignore               // Git 忽略文件列表
├── env.d.ts。               // 为用户自定义环境变量提供 TypeScript 智能提示
├── index.html           		 // 入口 HTML 文件
├── package.json             // 项目配置文件
├── README.md                // 项目说明文件
├── tsconfig.json            // TypeScript 配置文件
├── tsconfig.node.json       // 为 Node.js 环境提供单独的TypeScript编译选项
└── vite.config.js					 // Vite的配置文件，用于配置开发环境和生产环境的各种选项
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br></div></div><h4 id="二、安装依赖"><a href="#二、安装依赖" class="header-anchor">#</a> 二、安装依赖</h4> <p>按命令序列的前两条命令进行操作：</p> <div class="language-bash line-numbers-mode"><pre class="language-bash"><code><span class="token builtin class-name">cd</span> realworld-frontend	 <span class="token comment"># 进入项目文件夹</span>
<span class="token function">pnpm</span> <span class="token function">install</span>  <span class="token comment"># 安装依赖（推荐）</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>依赖安装完成后，项目文件夹 RealWorld-frontend 中将多出一个子文件夹 node_modules：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>├── node_modules/            // 第三方依赖包目录
├── public/                  
├── src/                     
│   ...
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>node_modules 文件夹里面就是按照 package.json 的指示下载的各种依赖。</p> <h3 id="运行单页应用"><a href="#运行单页应用" class="header-anchor">#</a> 运行单页应用</h3> <h4 id="一、启动项目服务端"><a href="#一、启动项目服务端" class="header-anchor">#</a> 一、启动项目服务端</h4> <p>项目服务端先启动起来，才能对浏览器端提供网页服务。启动命令为：<code>pnpm dev</code> 或 <code>npm run dev</code></p> <p>启动成功后，屏幕显示：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>  VITE v4.2.1  ready in 416 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h to show help
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>表明项目服务端已经运行在 5173 端口，等待浏览器的访问。</p> <h4 id="二、从浏览器访问应用"><a href="#二、从浏览器访问应用" class="header-anchor">#</a> 二、从浏览器访问应用</h4> <p>按住 Ctrl 键，并用鼠标单击链接 <code>http://localhost:5173/</code>，将在浏览器中打开应用的首页，内容如下图所示。</p> <p><img alt="image" data-src="https://cdn.jsdelivr.net/gh/cmty256/imgs-blog@main/microservice/image.7ksir8j4wlk0.webp" loading="lazy" class="lazy"></p> <h2 id="任务二-了解组合式-api"><a href="#任务二-了解组合式-api" class="header-anchor">#</a> 任务二 了解组合式 API</h2> <p>当使用 Vue 2 的 Options API 进行大型项目开发时，可能会遇到<strong>代码复杂度高、难以维护的问题</strong>。为了解决这个问题，Vue 3 提供了一种新的组件编写方式：<code>组合式 API</code> 和 <code>setup() 函数</code>。</p> <ul><li><code>组合式 API</code> 允许按照逻辑组织代码，而不是按照生命周期函数或选项来组织代码，从而提高了代码的可读性和可维护性。</li> <li><code>setup() 函数</code>在组件创建和挂载之前运行，用于设置组件的响应式数据、计算属性、方法和监听器等。在 <code>setup() 函数</code>中，可以使用 Vue 3 的组合式 API 如 ref、reactive、computed、watchEffect 等来实现组件的逻辑，从而更好地组织项目代码。</li></ul> <h3 id="使用-setup-函数"><a href="#使用-setup-函数" class="header-anchor">#</a> 使用 setup 函数</h3> <p>Vue 3 中的 <code>setup() 函数</code>是使用<code>组合式 API</code> 编写组件的入口函数，它会在组件实例创建之前被调用。</p> <p>在 <code>setup() 函数</code>内部，可以通过使用 Vue 3 提供的一系列<code>组合式 API</code> 来定义组件的响应式数据、计算属性、方法等等，并将它们返回给组件的模板中使用。<code>setup() 函数</code>返回的对象会被用作组件实例的数据对象，可以在模板中直接访问。</p> <p>以下是一个简单的例子，演示了如何使用 Vue 3 的 <code>setup() 函数</code> 和 <code>reactive()</code> 来创建一个响应式的计数器：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>当前计数：{{ state.count }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>increment<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>+ 1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
  
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> reactive <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
    <span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> state <span class="token operator">=</span> <span class="token function">reactive</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
            <span class="token literal-property property">count</span><span class="token operator">:</span> <span class="token number">0</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>

        <span class="token keyword">const</span> <span class="token function-variable function">increment</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            state<span class="token punctuation">.</span>count<span class="token operator">++</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> <span class="token punctuation">{</span>
            state<span class="token punctuation">,</span>
            increment
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br></div></div><p>在上述代码中，</p> <ol><li>我们首先引入了 Vue 3 提供的 reactive 函数，用于创建响应式对象。</li> <li>在 setup() 函数中，我们使用 reactive 函数创建了一个名为 state 的响应式对象，包含了一个 count 属性。</li> <li>接着，我们定义了一个名为 increment 的方法，用于将 state 对象的 count 属性 +1。</li> <li>最后，我们将 state 和 increment 作为对象返回，供模板中使用。</li></ol> <p>由于使用了 reactive 函数，state 对象是响应式的，因此它的值会自动更新到模板中。当state.count 属性更新时，模板中的数据也会更新。</p> <p>同样的响应式也可以通过 <code>ref()</code> 实现：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>当前计数：{{ count }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>increment<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>+1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
    <span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> count <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>

        <span class="token keyword">const</span> <span class="token function-variable function">increment</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            count<span class="token punctuation">.</span>value<span class="token operator">++</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> <span class="token punctuation">{</span>
            count<span class="token punctuation">,</span>
            increment
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br></div></div><p><strong>由于 <code>setup() 函数</code>的执行时机早于 Vue 2 中的 created 钩子函数</strong>，可以在其中进行一些更早的初始化操作，提高组件的性能。</p> <p>总之，<code>setup() 函数</code>是 Vue 3 中使用<code>组合式 API</code>编写组件的重要入口函数，通过它可以更加自由地组织组件的逻辑，使得代码更加清晰易懂。</p> <h3 id="使用-script-setup"><a href="#使用-script-setup" class="header-anchor">#</a> 使用 script setup</h3> <ul><li><code>&lt;script setup&gt;</code> 是在单文件组件 (SFC) 中使用组合式 API 的编译时<strong>语法糖</strong>，用于简化组件的编写和组织。</li> <li>当同时使用 SFC 与组合式 API 时该语法是默认推荐。它允许在一个 <code>&lt;script&gt;</code> 标签内使用 <code>Composition API</code>，而<strong>不需要定义 <code>setup()</code> 函数或返回语句</strong>。</li> <li>它还提供了一些额外的功能，如自动导入和导出组件属性、响应式声明、类型推断等。</li></ul> <p>使用 <code>&lt;script setup&gt;</code> 可以让组件的代码更加清晰和高效。相比于普通的 <code>&lt;script&gt;</code> 语法，它具有更多优势：</p> <ul><li>更少的样板内容，更简洁的代码。</li> <li>能够使用纯 TypeScript 声明 props 和自定义事件。</li> <li>更好的运行时性能 (其模板会被编译成同一作用域内的渲染函数，避免了渲染上下文代理对象)。</li> <li>更好的 IDE 类型推导性能 (减少了语言服务器从代码中抽取类型的工作)。</li></ul> <p>下面是一个使用 <code>&lt;script setup&gt;</code> 的示例组件：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span>{{ title }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>increment<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Count: {{ count }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>

<span class="token comment">// 自动导出为组件属性</span>
<span class="token keyword">const</span> title <span class="token operator">=</span> <span class="token string">'Hello Vue 3'</span>

<span class="token comment">// 响应式声明</span>
<span class="token keyword">const</span> count <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>

<span class="token comment">// 普通函数</span>
<span class="token keyword">function</span> <span class="token function">increment</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  count<span class="token punctuation">.</span>value<span class="token operator">++</span>
<span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br></div></div><p>用 <code>&lt;script setup&gt;</code> 语法糖改写目标 1 的代码：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>当前计数：{{ count }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>increment<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>+1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>

<span class="token keyword">const</span> count <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> <span class="token function-variable function">increment</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  count<span class="token punctuation">.</span>value<span class="token operator">++</span>
<span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><p>可见，在 <code>&lt;script setup&gt;</code> 中 <code>setup()</code> 函数不用再写了，定义的变量和函数会自动暴露给模板，并且不需要再用 return 语句将它们导出。这样可以更简洁地编写 Vue 组件。</p> <h3 id="引入-typescript"><a href="#引入-typescript" class="header-anchor">#</a> 引入 TypeScript</h3> <p>在创建 Vue 3 + Vite 项目时，如果已经选择并安装了 “Add TypeScript”，那么就可以采用 TypeScript 编写组件，目标 2 中的代码用 TypeScript 可以改写为：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>当前计数：{{ count }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>increment<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>+1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>ts<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>

<span class="token keyword">const</span> count <span class="token operator">=</span> ref<span class="token operator">&lt;</span>number<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> <span class="token function-variable function">increment</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  count<span class="token punctuation">.</span>value<span class="token operator">++</span>
<span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><ul><li><code>&lt;script setup&gt;</code> 中的脚本可以使用 TypeScript 或 JavaScript 编写。这里我们写成 <code>&lt;script setup lang=&quot;ts&quot;&gt;</code>，其中 <code>lang=&quot;ts&quot;</code> 是告诉 Vue 3，该组件的脚本使用 TypeScript 编写。使用 <strong>TypeScript 可以提供更好的类型检查和代码提示，以及更好的代码可维护性和可读性</strong>。根据在 lang 属性中指定的语言类型，Vue 3 会相应地对组件进行编译处理。如果没有指定 <code>lang 属性</code>，则默认使用 JavaScript 编写脚本。</li> <li>在这里，<strong><code>ref&lt;number&gt;(0)</code> 表示将数字类型的值 0 转换为响应式对象</strong>。<code>&lt;number&gt;</code> 是 TypeScript 中的类型注解，用于指定 count 的类型为数字。这样在开发过程中，如果不小心给 count 赋予非数字类型的值，TypeScript 编译器就会提示错误。</li></ul> <h2 id="响应式"><a href="#响应式" class="header-anchor">#</a> 响应式</h2> <p>所谓响应式，就是当我们修改数据后，可以自动做某些事情；对应到组件的渲染，就是修改数据后，能自动触发组件的重新渲染。这其实是一种<strong>状态驱动</strong>，让用户界面随着数据变化而自动更新的编程范式。</p> <p>响应式的<strong>核心思想</strong>是将数据和视图绑定在一起，当数据发生变化时，视图也会相应地变化，而不需要手动操作 DOM 元素。</p> <p>响应式的<strong>优点</strong>是可以简化前端开发的复杂度，提高用户体验和性能，避免不必要的重绘和重排。响应式的实现方式有多种，比如使用观察者模式、发布订阅模式、虚拟 DOM 等。响应式的代表框架有 React、Vue.js、Angular 等。</p> <h3 id="vue-3-的响应式原理"><a href="#vue-3-的响应式原理" class="header-anchor">#</a> Vue 3 的响应式原理</h3> <p>Vue 3 的响应式原理是：基于 ES6 的 Proxy 和 Reflect 特性实现的，它可以对对象的各种操作进行拦截和处理，从而实现数据和视图的双向绑定。这个方法的本质是劫持了数据对象的读写。当我们访问数据时，会触发 getter 执行依赖收集；修改数据时，会触发 setter 派发通知。</p> <p>Vue 3 的响应式原理主要包括以下几个步骤：</p> <ol><li><p>创建一个响应式对象，使用 Proxy 对目标对象进行代理，拦截它的 get 和 set 操作，同时使用 Reflect 对操作进行反射，保证原对象的行为不受影响。</p></li> <li><p>在 get 操作中，收集依赖，即将当前的渲染函数或者副作用函数添加到目标对象的依赖集合中，这样当目标对象发生变化时，就可以通知这些函数进行更新。</p></li> <li><p>在 set 操作中，触发更新，即遍历目标对象的依赖集合，调用其中的函数，让它们重新执行，从而更新视图或者产生其他效果。</p></li> <li><p>重复以上步骤，实现数据和视图的动态响应。</p></li></ol> <p>Vue 3 的响应式原理相比于 Vue 2 的 <code>Object.defineProperty</code> 方式，有以下优势：</p> <ul><li>可以拦截更多的操作，如 delete、has、ownKeys 等，提高了灵活性和兼容性。</li> <li>可以对数组和嵌套对象进行响应式处理，无需额外的处理逻辑。</li> <li>可以避免原对象被污染，保持了数据的纯净性。</li> <li>可以提高性能，减少了不必要的依赖收集和更新触发。</li></ul> <h3 id="vue-3-的响应式-api"><a href="#vue-3-的响应式-api" class="header-anchor">#</a> Vue 3 的响应式 API</h3> <p>Vue 3 的响应式 api 是一组新的功能，用于创建和管理响应式数据。</p> <p>它们可以让我们在组件中更灵活地组织和复用逻辑，也可以与其他 Vue 特性（如计算属性、侦听器、生命周期钩子等）配合使用。</p> <p>Vue 3 的响应式 api 主要包括以下几个部分：</p> <ol><li>ref：用于<strong>创建一个响应式的值</strong>，可以是<strong>基本类型或对象类型</strong>。ref 返回一个包含 <code>.value</code> 属性的对象，通过这个属性可以访问或修改原始值。ref 也可以用于绑定模板中的 DOM 元素，通过 <code>.value</code> 获取元素的引用。</li> <li>reactive：用于<strong>创建一个响应式的对象</strong>，可以是普通对象、数组或类实例。reactive 返回一个代理对象，通过这个对象可以访问或修改原始对象的属性。reactive 不会改变原始对象的结构和身份，只是在访问和修改时触发响应式效果。</li> <li>computed：用于<strong>创建一个响应式的计算属性</strong>，可以根据其他响应式数据（如ref或reactive）动态地计算出一个值。computed 返回一个包含 <code>.value</code> 属性的对象，通过这个属性可以访问计算出的值。computed 也可以接受一个包含 get 和 set 函数的对象，实现可写的计算属性。</li> <li>watch：用于<strong>监听一个或多个响应式数据（如ref或reactive）的变化，并执行相应的回调函数</strong>。watch 可以接受一个源数据或一个返回源数据的函数作为第一个参数，以及一个回调函数作为第二个参数。watch 也可以接受一个包含多个源数据和回调函数的数组作为参数，实现同时监听多个数据。</li> <li>watchEffect：用于<strong>监听一个副作用函数中使用到的所有响应式数据的变化，并重新执行该函数</strong>。watchEffect 接受一个副作用函数作为参数，该函数会在首次调用时立即执行，并在后续任何依赖数据变化时重新执行。</li> <li>toRefs：用于<strong>将一个响应式对象（如reactive）转换为一个普通对象</strong>，该对象的每个属性都是一个 ref，指向原始对象的对应属性。toRefs 可以保持原始对象的响应性，同时避免解构时丢失响应性。</li> <li>toRaw：用于<strong>将一个响应式对象（如reactive）转换为原始对象，取消其响应性</strong>。toRaw 可以在需要直接操作原始对象而不触发响应式效果时使用。</li></ol> <h2 id="任务三-用-reactive-设置响应式数据"><a href="#任务三-用-reactive-设置响应式数据" class="header-anchor">#</a> 任务三 用 reactive 设置响应式数据</h2> <h3 id="reactive-函数的原理及注意事项"><a href="#reactive-函数的原理及注意事项" class="header-anchor">#</a> reactive 函数的原理及注意事项</h3> <p>在 Vue 3 中，我们可以使用 Composition API 中的 reactive 函数来构建响应式对象。</p> <p>这个函数接收一个普通对象作为参数，并返回一个响应式代理对象。这个代理对象包含了原始对象的所有属性，并且这些属性都是响应式的。当我们访问代理对象的属性时，实际上是在访问原始对象的属性，因此会触发 getter 执行依赖收集。当我们修改代理对象的属性时，实际上是在修改原始对象的属性，因此会触发 setter 派发通知。这种方式比 Vue 2.x 中使用的 <code>Object.defineProperty()</code> 实现响应式更加高效和灵活。</p> <ul><li><p>在使用 reactive 时，需要注意以下几点：</p></li> <li><p>只有在组件的 setup 函数中才能使用 reactive 函数。</p></li> <li><p>只有通过 reactive 函数创建的对象才是响应式数据对象，直接修改普通 JavaScript 对象的属性不会触发视图更新。</p></li> <li><p>reactive 函数只能处理对象类型数据，如果需要处理其他类型数据，可以使用 ref 函数。</p></li> <li><p>reactive 返回的是一个 Proxy 对象，而不是原始对象。</p></li> <li><p>reactive 返回的 Proxy 对象可以直接访问原始对象的属性和方法。</p></li> <li><p>reactive 返回的 Proxy 对象可以直接修改原始对象的属性和方法。</p></li> <li><p>reactive 返回的 Proxy 对象可以直接监听原始对象的变化。</p></li> <li><p>在模板中使用响应式对象的属性时，需要使用 <code>两个花括号</code> 语法来绑定数据，例如</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code>{{ state.list }}
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div></li> <li><p>响应式对象的属性需要在对象创建时就定义好，不能在后面动态添加或删除属性。如果需要动态添加或删除属性，可以使用 reactive 函数创建一个新的响应式对象。</p></li> <li><p>在开发时，<strong>建议</strong>使用 <code>toRefs</code> 函数将响应式对象转换成普通对象的引用。这可以使代码更加清晰易懂，同时也能避免一些潜在的问题。</p></li></ul> <h3 id="reactive-的使用举例"><a href="#reactive-的使用举例" class="header-anchor">#</a> reactive 的使用举例</h3> <h4 id="一、reactive-作用于普通的-javascript-对象"><a href="#一、reactive-作用于普通的-javascript-对象" class="header-anchor">#</a> 一、reactive 作用于普通的 JavaScript 对象</h4> <p>在 Vue 3 中，reactive 函数可以将一个普通的 JavaScript 对象转换成一个响应式数据对象，使得对象的属性可以被监听到变化并且自动更新视图。下面是 reactive 作用于对象的示例代码及注意事项：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeName<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>修改name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeAge<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>修改age<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeGender<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>修改gender<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">&gt;</span></span>
    {{ state.person.name }} - {{ state.person.age }} - {{ state.person.gender }}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> reactive <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>

<span class="token keyword">const</span> state <span class="token operator">=</span> <span class="token function">reactive</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">person</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Tom'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span><span class="token punctuation">,</span>
        <span class="token literal-property property">gender</span><span class="token operator">:</span> <span class="token string">'male'</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">// 修改响应式对象的name</span>
<span class="token keyword">function</span> <span class="token function">changeName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    state<span class="token punctuation">.</span>person<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">&quot;Linda&quot;</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>person<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token comment">// 输出 Linda</span>
<span class="token punctuation">}</span>

<span class="token comment">// 修改响应式对象的age</span>
<span class="token keyword">function</span> <span class="token function">changeAge</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    state<span class="token punctuation">.</span>person<span class="token punctuation">.</span>age<span class="token operator">++</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>person<span class="token punctuation">.</span>age<span class="token punctuation">)</span> <span class="token comment">// 输出 19</span>
<span class="token punctuation">}</span>

<span class="token comment">// 修改响应式对象的gender</span>
<span class="token keyword">function</span> <span class="token function">changeGender</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    state<span class="token punctuation">.</span>person<span class="token punctuation">.</span>gender <span class="token operator">=</span> <span class="token string">&quot;female&quot;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>person<span class="token punctuation">.</span>gender<span class="token punctuation">)</span> <span class="token comment">// 输出 female</span>
<span class="token punctuation">}</span>

</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br></div></div><p>注意事项：</p> <ul><li>对于一个普通的 JavaScript 对象，通过 reactive 函数可以将其转换成一个响应式数据对象，使得对象的属性可以被监听到变化并且自动更新视图。</li> <li>只有通过 reactive 函数创建的对象才是响应式数据对象，直接修改普通 JavaScript 对象的属性不会触发视图更新。</li> <li>响应式对象的属性需要在对象创建时就定义好，不能在后面动态添加或删除属性。如果需要动态添加或删除属性，可以使用 reactive 函数创建一个新的响应式对象。</li> <li>响应式对象的<strong>属性值如果是一个对象</strong>，需要使用 reactive 函数将其转换成响应式对象，否则其属性变化不会触发视图更新。</li></ul> <h4 id="二、reactive-作用于数组"><a href="#二、reactive-作用于数组" class="header-anchor">#</a> 二、reactive 作用于数组</h4> <p>在 Vue 3 中，reactive 函数也可以将一个普通的 JavaScript 数组转换成一个响应式数组，使得数组元素的变化可以被监听到并且自动更新视图。下面是一个 reactive 作用于数组的示例代码：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>change<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>修改元素<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>add<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>添加元素<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>del<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>删除元素<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">&gt;</span></span>
    {{ state.list }}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> reactive <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>

<span class="token keyword">const</span> state <span class="token operator">=</span> <span class="token function">reactive</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">list</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'apple'</span><span class="token punctuation">,</span> <span class="token string">'banana'</span><span class="token punctuation">,</span> <span class="token string">'orange'</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 修改响应式数组的元素</span>
<span class="token keyword">function</span> <span class="token function">change</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    state<span class="token punctuation">.</span>list<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">'pear'</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>list<span class="token punctuation">)</span>  <span class="token comment">// 输出 Proxy(Array) {0: 'pear', 1: 'banana', 2: 'orange'}</span>
<span class="token punctuation">}</span>

<span class="token comment">// 向响应式数组中添加元素</span>
<span class="token keyword">function</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    state<span class="token punctuation">.</span>list<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'grape'</span><span class="token punctuation">)</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>list<span class="token punctuation">)</span>  <span class="token comment">// 输出 Proxy(Array) {0: 'pear', 1: 'banana', 2: 'orange', 3: 'grape'}</span>
<span class="token punctuation">}</span>

<span class="token comment">// 从响应式数组中删除元素</span>
<span class="token keyword">function</span> <span class="token function">del</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    state<span class="token punctuation">.</span>list<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>list<span class="token punctuation">)</span>  <span class="token comment">// 输出 Proxy(Array) {0: 'pear', 1: 'orange', 2: 'grape'}</span>
<span class="token punctuation">}</span>

</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br></div></div><p>注意事项：</p> <ul><li>响应式数组的元素操作需要使用 JavaScript 数组的操作方法，如 push()、pop()、shift()、unshift()、splice() 等。</li> <li>对响应式数组的操作会自动触发视图更新，无需手动调用。</li> <li>如果直接修改响应式数组的长度，例如 <code>state.list.length = 2</code>，则会导致视图无法更新，需要使用数组的操作方法进行操作。</li> <li>对响应式数组进行操作时，<strong>需要保证操作前后引用的是同一个数组对象</strong>，否则会导致视图无法更新。例如，不要使用 <code>state.list = []</code> 的方式清空数组，而应该使用 <code>state.list.splice(0, state.list.length)</code> 的方式清空数组。</li></ul> <h2 id="任务四-用-ref-设置响应式数据"><a href="#任务四-用-ref-设置响应式数据" class="header-anchor">#</a> 任务四 用 ref 设置响应式数据</h2> <h3 id="ref-的原理及注意事项"><a href="#ref-的原理及注意事项" class="header-anchor">#</a> ref 的原理及注意事项</h3> <p>在 Vue 3 中，ref 是一个函数，用于创建一个响应式数据对象，它可以<strong>将一个普通的 <code>JavaScript 值</code>转换成一个响应式数据对象</strong>，并提供了对该数据对象的访问和修改方法，使得修改该对象的值可以自动触发视图更新。（包裹一个值，这个值可以是对象类型也可以是基本类型，最终都会被转化成一个响应式对象）</p> <p><strong>ref 是基于 reactive 实现的</strong>。具体来说，ref 函数接受一个普通值作为参数，内部会使用 reactive 创建一个响应式对象来包裹这个值。当我们通过 <code>.value</code> 访问 ref 对象时，实际上是访问这个内部的响应式对象的值。</p> <p>举个例子，以下代码展示了 ref 的实现原理：</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> reactive <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>

<span class="token keyword">function</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token function">reactive</span><span class="token punctuation">(</span><span class="token punctuation">{</span> value <span class="token punctuation">}</span><span class="token punctuation">)</span>

  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token keyword">get</span> <span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> obj<span class="token punctuation">.</span>value
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token keyword">set</span> <span class="token function">value</span><span class="token punctuation">(</span><span class="token parameter">newValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      obj<span class="token punctuation">.</span>value <span class="token operator">=</span> newValue
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><p>上面的代码中，ref 函数接受一个值作为参数，并使用 reactive 函数创建了一个包含该值的响应式对象 obj，然后返回一个包含 get 和 set 方法的对象，这两个方法用来获取和设置 <code>obj.value</code> 属性的值。</p> <p>当我们访问 ref 对象时，实际上是在访问这个对象的 value 属性，这个属性通过 <code>get</code> 方法返回 <code>obj.value</code>，<strong>当我们修改 ref 对象的值时，实际上是在修改这个对象内部响应式对象的值，这个操作通过 set 方法实现</strong>。</p> <p>因此，可以说 ref 是基于 reactive 实现的，它们都是 Vue 3 中用于创建响应式数据对象的重要函数。</p> <blockquote><p>在 Vue 3 中既然有了 reactive，为何还要 ref 呢？</p></blockquote> <p>当我们只想让某个变量实现响应式的时候，采用 reactive 就会比较麻烦，因此 Vue 3 提供了 ref 方法进行简单值的监听，但并不是说 ref 只能传入简单值，它的底层是 reactive，所以 reactive 有的，ref 都有。</p> <p>请牢牢记住：</p> <ul><li>ref 本质也是 reactive，<code>ref(obj)</code> <strong>等价于</strong> <code>reactive({value: obj})</code>。</li> <li>在 Vue 组件的 <code>&lt;script&gt;...&lt;/script&gt;</code> 标签中使用 ref 的值，<strong>必须</strong>通过 <code>.value</code> 获取。</li> <li>在 Vue 组件的 <code>&lt;template&gt;...&lt;/template&gt;</code> 标签中<strong>直接</strong>使用 ref 的值，<strong>不用也不能</strong>通过 <code>.value</code> 获取。</li></ul> <h3 id="ref-的使用举例"><a href="#ref-的使用举例" class="header-anchor">#</a> ref 的使用举例</h3> <blockquote><p>我们将前面用 reactive 实现的代码改为 ref 再实现一次：</p></blockquote> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeName<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>修改name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeAge<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>修改age<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeGender<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>修改gender<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">&gt;</span></span>
    {{ name }} - {{ age }} - {{ gender }}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span><span class="token punctuation">;</span>

<span class="token comment">// 包裹基本类型</span>
<span class="token keyword">const</span> name <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token string">'Tom'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> age <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token number">18</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> gender <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token string">'male'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 修改ref对象的name</span>
<span class="token keyword">function</span> <span class="token function">changeName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    name<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">&quot;Linda&quot;</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>name<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 输出 Linda</span>
<span class="token punctuation">}</span>

<span class="token comment">// 修改ref对象的age</span>
<span class="token keyword">function</span> <span class="token function">changeAge</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    age<span class="token punctuation">.</span>value<span class="token operator">++</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>age<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 输出 19</span>
<span class="token punctuation">}</span>

<span class="token comment">// 修改ref对象的gender</span>
<span class="token keyword">function</span> <span class="token function">changeGender</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    gender<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">&quot;female&quot;</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>gender<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 输出 female</span>
<span class="token punctuation">}</span>

</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br></div></div><p>在上面的代码中，我们使用 ref 分别创建了三个响应式数据 name、age 和 gender，它们的初始值分别为 'Tom'、18 和 'male'。同时，我们也将修改数据的三个函数 changeName、changeAge 和 changeGender 进行了相应的修改，使用 ref 对象的 <code>.value</code> 属性来修改值。</p> <p>通过这种方式，我们可以将原本使用 reactive 实现的代码转换为使用 ref 实现的代码，这样做可以使代码更加简洁和直观，同时也方便我们进行数据的管理和修改。</p> <blockquote><p>前面说过，ref 函数并不只限于定义简单值，它仍然可以作用于对象。现在我们用 <code>ref(obj)</code> 的方式改写刚才的代码：</p></blockquote> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeName<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>修改name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeAge<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>修改age<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeGender<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>修改gender<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">&gt;</span></span>
    {{ person.name }} - {{ person.age }} - {{ person.gender }}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>

<span class="token keyword">const</span> person <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Tom'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span><span class="token punctuation">,</span>
    <span class="token literal-property property">gender</span><span class="token operator">:</span> <span class="token string">'male'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 修改ref对象的name</span>
<span class="token keyword">function</span> <span class="token function">changeName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    person<span class="token punctuation">.</span>value<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">&quot;Linda&quot;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>person<span class="token punctuation">.</span>value<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token comment">// 输出 Linda</span>
<span class="token punctuation">}</span>

<span class="token comment">// 修改ref对象的age</span>
<span class="token keyword">function</span> <span class="token function">changeAge</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    person<span class="token punctuation">.</span>value<span class="token punctuation">.</span>age<span class="token operator">++</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>person<span class="token punctuation">.</span>value<span class="token punctuation">.</span>age<span class="token punctuation">)</span> <span class="token comment">// 输出 19</span>
<span class="token punctuation">}</span>

<span class="token comment">// 修改ref对象的gender</span>
<span class="token keyword">function</span> <span class="token function">changeGender</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    person<span class="token punctuation">.</span>value<span class="token punctuation">.</span>gender <span class="token operator">=</span> <span class="token string">&quot;female&quot;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>person<span class="token punctuation">.</span>value<span class="token punctuation">.</span>gender<span class="token punctuation">)</span> <span class="token comment">// 输出 female</span>
<span class="token punctuation">}</span>

</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br></div></div><p>在修改 person 对象的属性时，需要使用 <code>person.value</code> 来访问内部的对象。</p> <h2 id="任务五-toref-与-torefs"><a href="#任务五-toref-与-torefs" class="header-anchor">#</a> 任务五 toRef() 与 toRefs()</h2> <h3 id="toref-的使用场景"><a href="#toref-的使用场景" class="header-anchor">#</a> toRef() 的使用场景</h3> <h4 id="_1-问题引入"><a href="#_1-问题引入" class="header-anchor">#</a> 1 问题引入</h4> <p>先来看看下面的代码有什么问题：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Name: {{ user.name }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Age: {{ user.age }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Gender: {{ user.gender }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeInfo<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Change Info<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>ts<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">

<span class="token keyword">interface</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> string<span class="token punctuation">;</span>
  <span class="token literal-property property">age</span><span class="token operator">:</span> number<span class="token punctuation">;</span>
  <span class="token literal-property property">gender</span><span class="token operator">:</span> string<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> <span class="token literal-property property">user</span><span class="token operator">:</span> User <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'John'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">25</span><span class="token punctuation">,</span>
  <span class="token literal-property property">gender</span><span class="token operator">:</span> <span class="token string">'male'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">changeInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  user<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'Mary'</span>
  user<span class="token punctuation">.</span>age <span class="token operator">=</span> <span class="token number">30</span>
  user<span class="token punctuation">.</span>gender <span class="token operator">=</span> <span class="token string">'female'</span>
<span class="token punctuation">}</span>

</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br></div></div><p>这段代码存在的问题是：在 Vue3 中使用了非响应式的对象 user。由于 user 对象是普通的 JavaScript 对象，而不是 Vue 的响应式对象，所以当 <code>changeInfo()</code> 函数修改了 user 对象的属性时，<strong>界面不会更新</strong>。</p> <h4 id="_2-解决办法"><a href="#_2-解决办法" class="header-anchor">#</a> 2 解决办法</h4> <p>解决方法是使用 Vue 的响应式对象来代替普通 JavaScript 对象，例如使用 <code>reactive()</code> 函数来创建一个响应式对象。可以将 user 对象改为以下代码：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Name: {{ user.name }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Age: {{ user.age }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Gender: {{ user.gender }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeInfo<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Change Info<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>ts<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> reactive <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>
<span class="token keyword">interface</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> string<span class="token punctuation">;</span>
  <span class="token literal-property property">age</span><span class="token operator">:</span> number<span class="token punctuation">;</span>
  <span class="token literal-property property">gender</span><span class="token operator">:</span> string<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token function">reactive</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'John'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">25</span><span class="token punctuation">,</span>
  <span class="token literal-property property">gender</span><span class="token operator">:</span> <span class="token string">'male'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function">changeInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  user<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'Mary'</span>
  user<span class="token punctuation">.</span>age <span class="token operator">=</span> <span class="token number">30</span>
  user<span class="token punctuation">.</span>gender <span class="token operator">=</span> <span class="token string">'female'</span>
<span class="token punctuation">}</span>

</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br></div></div><p>这段代码确实实现了页面的同步更新，但模板里反复使用 <code>user.前缀</code> 显得有些冗余，如何减少模板中重复使用 <code>user.前缀</code> 的情况，从而提高了代码的可读性呢？</p> <h4 id="_3-继续改进"><a href="#_3-继续改进" class="header-anchor">#</a> 3 继续改进</h4> <p>toRef 是 Vue3 中的一个工具函数，用于<strong>将响应式对象上的一个属性转换为一个单独的 ref 对象</strong>。我们尝试用它来减少模板中 user. 前缀的重复使用，代码如下：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Name: {{ name }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span> // 少了前缀
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Age: {{ age }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Gender: {{ gender }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeInfo<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Change Info<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>ts<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> reactive<span class="token punctuation">,</span> toRef <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>

<span class="token keyword">interface</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> string<span class="token punctuation">;</span>
  <span class="token literal-property property">age</span><span class="token operator">:</span> number<span class="token punctuation">;</span>
  <span class="token literal-property property">gender</span><span class="token operator">:</span> string<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> <span class="token literal-property property">user</span><span class="token operator">:</span> User <span class="token operator">=</span> <span class="token function">reactive</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'John'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">25</span><span class="token punctuation">,</span>
  <span class="token literal-property property">gender</span><span class="token operator">:</span> <span class="token string">'male'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> name <span class="token operator">=</span> <span class="token function">toRef</span><span class="token punctuation">(</span>user<span class="token punctuation">,</span> <span class="token string">'name'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> age <span class="token operator">=</span> <span class="token function">toRef</span><span class="token punctuation">(</span>user<span class="token punctuation">,</span> <span class="token string">'age'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> gender <span class="token operator">=</span> <span class="token function">toRef</span><span class="token punctuation">(</span>user<span class="token punctuation">,</span> <span class="token string">'gender'</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function">changeInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  name<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">'Mary'</span>
  age<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token number">30</span>
  gender<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">'female'</span>
<span class="token punctuation">}</span>

</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br></div></div><p>当我们使用 <code>toRef()</code> 将一个响应式对象 user 的属性转化为 ref 后，该 ref 会与源对象的属性保持同步。这样创建的 ref 对象与其源属性保持同步：改变源属性的值将更新 ref 的值，反之亦然。</p> <h3 id="torefs-的使用场景"><a href="#torefs-的使用场景" class="header-anchor">#</a> toRefs() 的使用场景</h3> <h4 id="一、问题引入"><a href="#一、问题引入" class="header-anchor">#</a> 一、问题引入</h4> <p>在上面示例 3 的代码中，如果对象的属性很多，每个属性都要保持响应性，那么势必多次调用 <code>toRef()</code> 函数，有没有什么办法可以一次性将响应式对象上的所有属性都转换为 ref 对象，从而简化代码呢？</p> <h4 id="二、解决办法"><a href="#二、解决办法" class="header-anchor">#</a> 二、解决办法</h4> <p>使用 Vue3 的 <code>toRefs()</code> 函数可以<strong>一次性将响应式对象上的所有属性都转换为 ref 对象</strong>，并使用对象解构语法来进一步简化代码，代码如下：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Name: {{ name }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Age: {{ age }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Gender: {{ gender }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>changeInfo<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Change Info<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>ts<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> reactive<span class="token punctuation">,</span> toRefs <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>

<span class="token keyword">interface</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> string<span class="token punctuation">;</span>
  <span class="token literal-property property">age</span><span class="token operator">:</span> number<span class="token punctuation">;</span>
  <span class="token literal-property property">gender</span><span class="token operator">:</span> string<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> <span class="token literal-property property">user</span><span class="token operator">:</span> User <span class="token operator">=</span> <span class="token function">reactive</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'John'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">25</span><span class="token punctuation">,</span>
  <span class="token literal-property property">gender</span><span class="token operator">:</span> <span class="token string">'male'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> stateRefs <span class="token operator">=</span> <span class="token function">toRefs</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> gender <span class="token punctuation">}</span> <span class="token operator">=</span> stateRefs

<span class="token keyword">function</span> <span class="token function">changeInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  name<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">'Mary'</span>
  age<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token number">30</span>
  gender<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">'female'</span>
<span class="token punctuation">}</span>

</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br></div></div><p>这段代码中使用 <code>toRefs(user)</code> 将响应式对象 user 中的所有属性（即name、age和gender）转换成对应的 ref 对象，并返回一个由这些 ref 对象组成的对象，这些 ref 对象的变化也会影响原响应式对象的属性。</p> <p>然后使用<strong>对象解构</strong>将它们分别赋值给 name、age 和 gender，这样，我们在模板中就可以直接访问这三个变量，而不用写成 stateRefs.name、stateRefs.age 和 stateRefs.gender 的形式。在 changeInfo 函数中，直接修改 name.value、age.value 和 gender.value 的值，这些值的变化会直接反映到原响应式对象 user 的属性上，从而触发页面的更新。</p> <h2 id="任务六-computed-与计算属性"><a href="#任务六-computed-与计算属性" class="header-anchor">#</a> 任务六 computed 与计算属性</h2> <h3 id="基本概念"><a href="#基本概念" class="header-anchor">#</a> 基本概念</h3> <p><code>computed 函数</code>，是一个响应式 API，类似于 Vue2.x 中的 <code>computed 属性</code>。使用 computed 函数可以让代码更加简洁和高效。</p> <p>computed 函数的值就是计算属性。computed 函数可以使用响应式依赖来创建计算属性，计算属性会自动追踪响应式依赖，在其任何响应式依赖项更改时自动重新计算。</p> <p>在模板中绑定计算属性，当计算属性的值发生变化时，会触发组件的重新渲染。在模板中绑定计算属性的另一个好处是，可以在模板中声明性地指定复杂的逻辑，而不必手动更新值或在代码中执行计算。</p> <h3 id="使用计算属性"><a href="#使用计算属性" class="header-anchor">#</a> 使用计算属性</h3> <p>计算属性的使用场景。</p> <p>例如，考虑一个简单的 Vue 3 组件，该组件显示一个商品列表和这些商品的总数：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">v-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>isLoading<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Loading...<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">v-else</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>item in goods<span class="token punctuation">&quot;</span></span> <span class="token attr-name">:key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>item.id<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{{ item.name }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>商品总数: {{ totalGoods }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>ts<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> computed<span class="token punctuation">,</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>

<span class="token keyword">interface</span> <span class="token class-name">Item</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">id</span><span class="token operator">:</span> number<span class="token punctuation">;</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> string<span class="token punctuation">;</span>
  <span class="token literal-property property">price</span><span class="token operator">:</span> number<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> goods <span class="token operator">=</span> ref<span class="token operator">&lt;</span>Item<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> isLoading <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> goods<span class="token punctuation">.</span>value<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> totalGoods <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> goods<span class="token punctuation">.</span>value<span class="token punctuation">.</span>length
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> baseUrl <span class="token operator">=</span> <span class="token string">'http://localhost:3000'</span>

<span class="token keyword">const</span> <span class="token function-variable function">fetchGoods</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span>baseUrl <span class="token operator">+</span> <span class="token string">'/goods'</span><span class="token punctuation">)</span>
    <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    goods<span class="token punctuation">.</span>value <span class="token operator">=</span> data <span class="token keyword">as</span> Item<span class="token punctuation">[</span><span class="token punctuation">]</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'an error happened'</span> <span class="token operator">+</span> e<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token function">fetchGoods</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br></div></div><p>在这个例子中，totalGoods 计算属性函数负责计算 goods 数组中的商品总数。<code>isLoading</code> 计算属性基于 goods 数组的长度返回一个布尔值，指示组件是否处于加载状态。</p> <p>请注意，这里使用计算属性 <code>isLoading</code> 来定义应用程序是否正在加载。通常，很多开发人员会定义 <code>isLoading</code> 变量，并在调用 <code>fetchGoods</code> 时将变量 <code>isLoading</code> 设置为 <code>true</code>，然后在 API 请求完成后再将其设置为 <code>false</code>。比如：</p> <div class="language-vue line-numbers-mode"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>ts<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">

<span class="token keyword">const</span> isLoading <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span>
<span class="token comment">// ...</span>
<span class="token keyword">const</span> <span class="token function-variable function">fetchGoods</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    isLoading<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token boolean">true</span>
    <span class="token comment">// 网络访问的代码 </span>
    <span class="token comment">// ...</span>
    isLoading<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token boolean">false</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  	<span class="token comment">// ...</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token function">fetchGoods</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br></div></div><p>相对于 Goods02.vue，Goods.vue 使用计算属性实现了 Loading 的<strong>显示逻辑与商品数据获取逻辑之间的解耦</strong>。</p></div></div> <!----> <div class="page-edit"><!----> <!----> <div class="last-updated"><span class="prefix">上次更新:</span> <span class="time">2024/6/3 14:54:44</span></div></div> <div class="page-nav-wapper"><div class="page-nav-centre-wrap"><a href="/pages/803f9d/" class="page-nav-centre page-nav-centre-prev"><div class="tooltip">Vue3入门</div></a> <a href="/pages/50e8d3/" class="page-nav-centre page-nav-centre-next"><div class="tooltip">黑马Vue3</div></a></div> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/pages/803f9d/" class="prev">Vue3入门</a></span> <span class="next"><a href="/pages/50e8d3/">黑马Vue3</a>→
      </span></p></div></div></div> <!----></main></div> <div class="footer"><!----> 
  Theme by
  <a href="https://github.com/xugaoyi/vuepress-theme-vdoing" target="_blank" title="本站主题">Vdoing</a> 
    | Copyright © 2023-2025
    <span>霜晨月</span></div> <div class="buttons"><div title="返回顶部" class="button blur go-to-top iconfont icon-fanhuidingbu" style="display:none;"></div> <div title="去评论" class="button blur go-to-comment iconfont icon-pinglun" style="display:none;"></div> <div title="主题模式" class="button blur theme-mode-but iconfont icon-zhuti"><ul class="select-box" style="display:none;"><li class="iconfont icon-zidong">
          跟随系统
        </li><li class="iconfont icon-rijianmoshi">
          浅色模式
        </li><li class="iconfont icon-yejianmoshi">
          深色模式
        </li><li class="iconfont icon-yuedu">
          阅读模式
        </li></ul></div></div> <!----> <!----> <!----></div><div class="global-ui"><canvas id="vuepress-canvas-cursor"></canvas></div></div>
    <script src="/assets/js/app.67adcfd9.js" defer></script><script src="/assets/js/4.9aaa1650.js" defer></script><script src="/assets/js/1.5474518c.js" defer></script><script src="/assets/js/3.593d14fc.js" defer></script><script src="/assets/js/171.38820827.js" defer></script>
  </body>
</html>
